package com.hthl.websocket;

import com.alibaba.fastjson.JSONObject;
import com.hthl.config.ApplicationContextProvider;
import com.hthl.config.JwtKey;
import com.hthl.entity.CollectData;
import com.hthl.entity.OfflineData;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Component;

import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.List;

/**
 * web socket 推送业务
 *
 * @author 刘青友
 */
@Component
@ServerEndpoint(value = "/realData")
@Slf4j
public class RealDataTransPort {

    // 当前会话连接
    private volatile Session session;

    private MongoTemplate mongoTemplate = ApplicationContextProvider.getBean(MongoTemplate.class);

    @OnOpen
    public void onOpen(Session session) {
        log.info("==========================有一用户发起连接，当前连接数为：" + SessionHolder.getCachedSessions().size());
    }

    @OnClose
    public void onClose() {
        SessionHolder.removeCachedSessions(this.session);
        log.error("==========================有一连接掉线，当前连接总数：" + SessionHolder.getCachedSessions().size());
    }

    @OnMessage
    public void onMessage(String message, Session session) throws IOException {
        log.info("=======================接收到客户端消息：" + message);
        // jwt密签不是使用utf-8解签，需要自己指定
        Claims claims = null;
        try {
            claims = Jwts.parser().setSigningKey(JwtKey.JWT_SIGNING_KEY.getBytes("UTF-8")).parseClaimsJws(message.replace("Bearer ", "")).getBody();
        } catch (Exception e) {
            log.error("解析token 异常", e);
            session.getBasicRemote().sendText("非法登录");
            session.close();
        }
        Integer enterpriseId = Integer.parseInt(claims.get("enterpriseId").toString());
        if (enterpriseId == null) {
            try {
                session.getBasicRemote().sendText("验证失败，连接被强制关闭");
                session.close();
            } catch (IOException e) {
                log.error("解析token 异常", e);
            }
        }
        this.session = session;
        SessionHolder.addCachedSessions(session, enterpriseId);
        firstOnlineMsgSend(session, enterpriseId);
        firstOfflineMsgSend(session, enterpriseId);
    }


    private void firstOnlineMsgSend(Session session, Integer enterpriseId) throws IOException {
        Query query = new Query();
        Criteria criteria = new Criteria();
        criteria.orOperator(Criteria.where("enterpriseId").is(enterpriseId),
                Criteria.where("useEnterpriseId").is(enterpriseId), Criteria.where("partnerId").in(enterpriseId));
        query.addCriteria(criteria);
        List<CollectData> collectDatas = mongoTemplate.find(query, CollectData.class);
        if (CollectionUtils.isEmpty(collectDatas)) {
            return;
        }
        for (CollectData collectData : collectDatas) {
            if (isAlarm(collectData)) {
                collectData.setType(CollectData.Type.ALARM.ordinal());
            }
            session.getBasicRemote().sendText(JSONObject.toJSONString(collectData));
        }
    }

    /**
     * $isAlarm 判断是否报警
     *
     * @param collectData 采集的数据集合
     * @return true 含有报警信息  false 不含有报警信息
     */
    private boolean isAlarm(CollectData collectData) {
        if (CollectionUtils.isEmpty(collectData.getDataDetailVos())) {
            return false;
        }
        for (CollectData.ParamDetail paramDetail : collectData.getDataDetailVos()) {
            if (paramDetail.getAlarmType() != null) {
                return true;
            }
        }
        return false;
    }

    private void firstOfflineMsgSend(Session session, Integer enterpriseId) throws IOException {
        Query query = new Query();
        Criteria criteria = new Criteria();
        criteria.orOperator(Criteria.where("enterpriseId").is(enterpriseId),
                Criteria.where("useEnterpriseId").is(enterpriseId), Criteria.where("partnerId").in(enterpriseId));
        query.addCriteria(criteria);
        List<OfflineData> offlineDatas = mongoTemplate.find(query, OfflineData.class);
        for (OfflineData offlineData : offlineDatas) {
            session.getBasicRemote().sendText(JSONObject.toJSONString(offlineData));
        }
    }

}
